package com.ternnetwork.auth.server.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import com.ternnetwork.auth.server.integration.IntegrationAuthenticationFilter;






/**
 * auth2认证服务器配置
 * @author xuwenfeng
 *
 */
@Configuration
@EnableAuthorizationServer
public class OauthConfiguration extends AuthorizationServerConfigurerAdapter {
	
		@Autowired
		private AuthenticationManager authenticationManager;
		
		
	    @Autowired
	    private DataSource dataSource;
	
	    @Autowired
	    private RedisConnectionFactory redisConnectionFactory;
	    
	
		@Autowired
		private UserDetailsService userDetailsService;
		
		
		@Autowired
		private PasswordEncoder passwordEncoder;
		
		
		@Autowired
		private IntegrationAuthenticationFilter integrationAuthenticationFilter;

	
		
		/**
		 * 客户端配置，如浏览器、zuul服务器
		 * 如果客户端名称与客户端密码有变动，
		 * 则请求端头也相应要变动，即Authorization的值要相应变化
		 * 此应用的app.js中如下行中的Authorization对应的值Basic enV1bF9zZXJ2ZXI6c2VjcmV0 需要改动 
		 * $httpProvider.defaults.headers.common={'Authorization' :'Basic enV1bF9zZXJ2ZXI6c2VjcmV0' }
		 * Authorization的值可以在注掉 $httpProvider.defaults.headers.common 此行后，刷新页面
		 * 会让你输入客户端名称与密码，然后可以用开发者工具查看请求头，就可以看到Authorization的值
		 */
		@Override
	    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
	        clients
	        .inMemory()
	        //设置客户端名称， 
	        .withClient("zuul_server")
	        //设置客户端密码
	        .secret(passwordEncoder.encode("secret"))
	        //访问域，必填
	        .scopes("read")
	        //设置token有效期
            .accessTokenValiditySeconds(7 * 24 * 3600)
            //设置refreshToken有效期
            .refreshTokenValiditySeconds(7 * 24 * 3600)
            //支持的认证方式
	        .authorizedGrantTypes("implicit", "refresh_token", "password", "authorization_code");
	    }
		
		@Override
	    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
	        endpoints
	        .tokenGranter(new CustomResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()))
	        //指定认证管理器
            .authenticationManager(authenticationManager)
            //用户账号密码认证
            .userDetailsService(userDetailsService)
            // refresh_token
            .reuseRefreshTokens(true)
            //指定token存储位置
            .tokenStore(redisTokenStore())
            // 配置JwtAccessToken转换器
            .accessTokenConverter(jwtTokenConverter());
	       
	        
	       
	    }
		
		
	    @Override
		 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		        security.allowFormAuthenticationForClients()
		                .tokenKeyAccess("isAuthenticated()")
		                .checkTokenAccess("permitAll()")
		                .addTokenEndpointAuthenticationFilter(integrationAuthenticationFilter);
		 }
		 
	    @Bean
	    public ClientDetailsService clientDetails() {
	        return new JdbcClientDetailsService(dataSource);
	    }

	    @Bean
	    public TokenStore jwtTokenStore() {
	        return new JwtTokenStore(jwtTokenConverter());
	    }
	    
	    @Bean
	    protected JwtAccessTokenConverter jwtTokenConverter() {
	        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
	        converter.setSigningKey("QWERFDSAZXCV");
	        return converter;
	    }
	    
	    
	   @Bean
	    public TokenStore redisTokenStore() {
	        return new RedisTokenStore(redisConnectionFactory);
	    }
	   
		
	
}
